Popular Searches
Popular Course Categories
Popular Courses

Cloud Firestore

Firebase with Flutter

Cloud Firestore in Flutter

Cloud Firestore is a flexible, scalable NoSQL cloud database provided by Firebase. It stores application data in collections and documents and allows Flutter applications to create, read, update, delete, query, and listen to data in real time.

Cloud Firestore can be used for applications such as user profiles, products, orders, chat applications, task management systems, social applications, blogs, booking systems, and dashboards. It supports real-time updates, expressive queries, hierarchical data structures, and offline capabilities. Firebase Cloud Firestore Documentation


1. What is Cloud Firestore?

Cloud Firestore is a NoSQL document database designed for mobile, web, and server applications. Instead of storing data in traditional rows and columns, Firestore stores data inside documents that are organized into collections.

For example, a users collection may contain multiple user documents:

users
├── user001
├── user002
├── user003
└── user004

Each document can contain fields such as name, email, age, phone number, and other application-specific information.


2. Firestore Data Model

The basic structure of Cloud Firestore is:

Firestore
   |
   +-- Collection
        |
        +-- Document
             |
             +-- Fields
             |
             +-- Subcollection

Example

users
  |
  +-- user123
       |
       +-- name: "John"
       +-- email: "[email protected]"
       +-- age: 25
       |
       +-- orders
            |
            +-- order001
            +-- order002

3. Collection

A collection is a group of related documents.

For example:

users
products
orders
messages
courses

A collection contains documents, and each document contains fields and values.


4. Document

A document is a record containing fields and values.

Example:

{
  "name": "John Doe",
  "email": "[email protected]",
  "age": 25,
  "isActive": true
}

A document has a unique document ID within its collection.


5. Fields

Fields contain the actual values stored inside a document.

Field Example Value Type
name John Doe String
age 25 Number
isActive true Boolean
skills ["Flutter","Dart"] Array
address {city: "Mumbai"} Map
createdAt Timestamp Timestamp

6. Subcollections

A document can contain subcollections. Subcollections are useful when data logically belongs to a particular document.

For example:

users
  |
  +-- user123
       |
       +-- name: "John"
       +-- email: "[email protected]"
       |
       +-- orders
            |
            +-- order001
            +-- order002

Here, orders is a subcollection inside the user123 document.


7. Why Use Cloud Firestore with Flutter?

  • Cloud-hosted NoSQL database.
  • Easy integration with Flutter through the Firebase FlutterFire plugin.
  • Supports real-time data updates.
  • Supports one-time data reads.
  • Supports filtering and sorting.
  • Supports hierarchical collections and subcollections.
  • Provides offline data support on supported platforms.
  • Integrates with Firebase Authentication.
  • Can be protected with Firebase Security Rules.
  • Suitable for applications that need to scale.

Firestore supports flexible data structures, expressive queries, real-time listeners, and offline capabilities. Learn more about Cloud Firestore


8. Prerequisites

Before using Cloud Firestore in Flutter, you should have:

  • Flutter SDK installed.
  • A Flutter project.
  • A Firebase project.
  • Firebase configured with the Flutter application.
  • The Cloud Firestore database created in Firebase Console.

For current Firebase Flutter setup instructions, see Get Started with Firebase in Flutter.


9. Add Cloud Firestore to Flutter

From the Flutter project directory, run:

flutter pub add cloud_firestore

After adding the Firebase Flutter plugin, use flutterfire configure to configure the Firebase project for the application. Firebase Flutter Setup


10. Import Cloud Firestore

import 'package:cloud_firestore/cloud_firestore.dart';

11. Get Firestore Instance

The main Firestore instance can be accessed using FirebaseFirestore.instance.

final FirebaseFirestore db = FirebaseFirestore.instance;

You can also directly use:

FirebaseFirestore.instance

12. Initialize Firebase

Firebase should be initialized before using Firestore. In a typical FlutterFire project, Firebase initialization uses the generated firebase_options.dart configuration.

import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  runApp(const MyApp());
}

Important: Make sure Firebase is initialized before performing Firestore operations.


13. Create a Firestore Database

  1. Open Firebase Console.
  2. Select your Firebase project.
  3. Open Firestore Database.
  4. Create a database.
  5. Choose the appropriate database configuration and location.
  6. Configure Security Rules according to your application's requirements.

Firestore data can also be managed directly from the Firebase Console. Manage Cloud Firestore with Firebase Console


14. Add Data to Firestore

There are several ways to add data to Firestore. You can specify a document ID yourself or allow Firestore to generate one automatically. Add Data to Cloud Firestore


15. Add Document with Auto-Generated ID

The add() method creates a new document and automatically generates its document ID.

await FirebaseFirestore.instance
    .collection('users')
    .add({
  'name': 'John Doe',
  'email': '[email protected]',
  'age': 25,
});

The resulting structure may look like:

users
  |
  +-- automatically-generated-id
       |
       +-- name: John Doe
       +-- email: [email protected]
       +-- age: 25

16. Add Document with Custom ID

Use doc() when you want to specify the document ID.

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .set({
  'name': 'John Doe',
  'email': '[email protected]',
  'age': 25,
});

The document ID in this example is user001.


17. Set Data

The set() method writes data to a document.

final userRef = FirebaseFirestore.instance
    .collection('users')
    .doc('user001');

await userRef.set({
  'name': 'John Doe',
  'email': '[email protected]',
});

18. Set Data with Merge

When you want to update selected fields without replacing the complete document, you can use merge behavior.

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .set({
  'age': 26,
}, SetOptions(merge: true));

This keeps other existing fields in the document while updating the specified field.


19. Firestore Data Types

Firestore supports several common data types, including strings, booleans, numbers, arrays, maps, timestamps, null values, document references, and other supported types.

final data = {
  'name': 'John',
  'age': 25,
  'isStudent': false,
  'skills': ['Flutter', 'Dart'],
  'address': {
    'city': 'Mumbai',
    'country': 'India',
  },
  'createdAt': Timestamp.now(),
  'description': null,
};

20. Read a Single Document

Use get() to retrieve a document once.

final doc = await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .get();

if (doc.exists) {
  print(doc.data());
}

Firestore supports one-time reads as well as real-time listeners. Get Data with Cloud Firestore


21. Access Document Data

final doc = await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .get();

final data = doc.data();

if (data != null) {
  print(data['name']);
  print(data['email']);
  print(data['age']);
}

22. Check Whether a Document Exists

final doc = await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .get();

if (doc.exists) {
  print('Document exists');
} else {
  print('Document does not exist');
}

23. Read All Documents from a Collection

Use a collection reference and get() to retrieve documents from a collection.

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .get();

for (final doc in snapshot.docs) {
  print(doc.id);
  print(doc.data());
}

24. Get Document ID

Each Firestore document has an ID that can be accessed through doc.id.

for (final doc in snapshot.docs) {
  print('Document ID: ${doc.id}');
}

25. Convert Firestore Data into a List

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .get();

final users = snapshot.docs.map((doc) {
  return {
    'id': doc.id,
    ...doc.data(),
  };
}).toList();

26. Display Firestore Data with FutureBuilder

FutureBuilder is useful for displaying data obtained through a one-time Firestore request.

FutureBuilder>>(
  future: FirebaseFirestore.instance
      .collection('users')
      .get(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const Center(
        child: CircularProgressIndicator(),
      );
    }

    if (snapshot.hasError) {
      return const Center(
        child: Text('Something went wrong'),
      );
    }

    if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
      return const Center(
        child: Text('No users found'),
      );
    }

    final users = snapshot.data!.docs;

    return ListView.builder(
      itemCount: users.length,
      itemBuilder: (context, index) {
        final user = users[index].data();

        return ListTile(
          title: Text(user['name'] ?? ''),
          subtitle: Text(user['email'] ?? ''),
        );
      },
    );
  },
)

27. Real-Time Firestore Data

Firestore supports real-time listeners. A listener receives an initial snapshot and then receives updates when the listened-to data changes.

FirebaseFirestore.instance
    .collection('users')
    .snapshots()
    .listen((snapshot) {
  for (final doc in snapshot.docs) {
    print(doc.data());
  }
});

Real-time listeners are useful for chat applications, live dashboards, notifications, collaborative applications, and other interfaces where data can change while the screen is open.


28. StreamBuilder with Firestore

StreamBuilder can be used to automatically rebuild the UI when Firestore data changes.

StreamBuilder>>(
  stream: FirebaseFirestore.instance
      .collection('users')
      .snapshots(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const Center(
        child: CircularProgressIndicator(),
      );
    }

    if (snapshot.hasError) {
      return const Center(
        child: Text('Error loading users'),
      );
    }

    final users = snapshot.data?.docs ?? [];

    if (users.isEmpty) {
      return const Center(
        child: Text('No users found'),
      );
    }

    return ListView.builder(
      itemCount: users.length,
      itemBuilder: (context, index) {
        final user = users[index].data();

        return ListTile(
          title: Text(user['name'] ?? ''),
          subtitle: Text(user['email'] ?? ''),
        );
      },
    );
  },
)

29. Update Firestore Data

The update() method changes selected fields in an existing document.

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .update({
  'age': 26,
  'isActive': true,
});

30. Update a Single Field

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .update({
  'name': 'John Smith',
});

31. Delete a Document

Use delete() to remove a document.

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .delete();

32. Delete a Field

You can remove a field from a document using FieldValue.delete().

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .update({
  'temporaryField': FieldValue.delete(),
});

33. Firestore CRUD Operations

CRUD stands for Create, Read, Update, and Delete.

Operation Firestore Method
Create add() / set()
Read get() / snapshots()
Update update()
Delete delete()

34. Query Firestore Data

Firestore queries allow you to retrieve only documents matching particular conditions. Queries can be combined with filtering, sorting, limits, and other supported query features. Cloud Firestore Query Documentation


35. Query Using where()

The where() method can filter documents based on field values.

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .where('age', isGreaterThan: 18)
    .get();

for (final doc in snapshot.docs) {
  print(doc.data());
}

36. Equality Query

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .where('city', isEqualTo: 'Mumbai')
    .get();

37. Multiple Query Conditions

Firestore supports compound queries when the selected fields and query structure are supported.

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .where('isActive', isEqualTo: true)
    .where('age', isGreaterThan: 18)
    .get();

Some compound queries may require an index. If Firestore requires an index, the error response can provide a link to create the required index.


38. Sorting Data with orderBy()

Use orderBy() to sort query results.

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .orderBy('name')
    .get();

Descending Order

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .orderBy('name', descending: true)
    .get();

39. Limit Query Results

Use limit() when you only need a specific number of documents.

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .limit(10)
    .get();

Limiting results can be useful for dashboards, previews, pagination, and performance-conscious screens.


40. Query with Multiple Conditions and Sorting

final snapshot = await FirebaseFirestore.instance
    .collection('products')
    .where('category', isEqualTo: 'Mobile')
    .where('price', isLessThan: 50000)
    .orderBy('price')
    .get();

Query structure must follow Firestore's query constraints and indexing requirements.


41. Query Using whereIn

Some queries can match a field against multiple values using supported operators such as whereIn.

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .where(
      'role',
      whereIn: ['admin', 'manager'],
    )
    .get();

42. Array Queries

For fields containing arrays, Firestore supports operators such as arrayContains.

final snapshot = await FirebaseFirestore.instance
    .collection('courses')
    .where(
      'skills',
      arrayContains: 'Flutter',
    )
    .get();

43. Search Example

A Firestore query can be used to filter data according to supported query operations.

final snapshot = await FirebaseFirestore.instance
    .collection('products')
    .where(
      'category',
      isEqualTo: 'Laptop',
    )
    .get();

For advanced full-text search requirements, a dedicated search solution may be more appropriate than relying on simple Firestore field filtering.


44. Firestore with Firebase Authentication

Cloud Firestore is commonly used together with Firebase Authentication. Authentication identifies the user, while Firestore stores application data associated with that user.

Example:

Authentication
      |
      v
Firebase User UID
      |
      v
Firestore
      |
      v
users/{uid}

Example

final user = FirebaseAuth.instance.currentUser;

if (user != null) {
  await FirebaseFirestore.instance
      .collection('users')
      .doc(user.uid)
      .set({
    'email': user.email,
    'name': 'John Doe',
  });
}

45. User-Specific Data

A common pattern is to use the authenticated user's UID as the Firestore document ID.

users
  |
  +-- AUTH_USER_UID
       |
       +-- name
       +-- email
       +-- phone
       +-- createdAt

This makes it straightforward to locate the current user's document.


46. Firestore Security Rules

Security Rules are essential for protecting Firestore data. For Flutter mobile and web clients, Firebase recommends using Firebase Authentication together with Cloud Firestore Security Rules to control access and validate data. Cloud Firestore Security Documentation

A basic authenticated-user rule can look like:

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null
                         && request.auth.uid == userId;
    }
  }
}

This pattern allows an authenticated user to access the user document whose ID matches their Firebase Authentication UID.


47. Important Security Rule Concept

Firestore Security Rules are not filters. A query must satisfy the constraints required by the rules for all potential documents that could be returned. A query that could return unauthorized documents can fail rather than simply filtering those documents out. Securely Query Cloud Firestore Data


48. Example of Query-Compatible Security

match /stories/{storyId} {
  allow read: if request.auth != null
              && resource.data.author == request.auth.uid;
}

The corresponding client query should constrain the author field:

final user = FirebaseAuth.instance.currentUser;

if (user != null) {
  final snapshot = await FirebaseFirestore.instance
      .collection('stories')
      .where(
        'author',
        isEqualTo: user.uid,
      )
      .get();
}

This query structure reflects the access condition enforced by the rule.


49. Server-Side Access vs Mobile/Web Access

Cloud Firestore Security Rules apply to supported mobile and web client access. Server client libraries use IAM and do not rely on Cloud Firestore Security Rules in the same way. Server-side applications should therefore be secured using the appropriate Google Cloud IAM configuration. Firestore Security Overview


50. Timestamp in Firestore

Firestore supports timestamp values.

await FirebaseFirestore.instance
    .collection('posts')
    .add({
  'title': 'Flutter Course',
  'createdAt': Timestamp.now(),
});

You can read the timestamp:

final data = doc.data();
final Timestamp? timestamp = data?['createdAt'];

if (timestamp != null) {
  final date = timestamp.toDate();
  print(date);
}

51. Server Timestamp

When you want Firestore to assign the server-side timestamp, use FieldValue.serverTimestamp().

await FirebaseFirestore.instance
    .collection('posts')
    .add({
  'title': 'Flutter Course',
  'createdAt': FieldValue.serverTimestamp(),
});

52. Increment Numeric Values

Firestore supports atomic numeric increments.

await FirebaseFirestore.instance
    .collection('products')
    .doc('product001')
    .update({
  'views': FieldValue.increment(1),
});

This can be useful for counters such as views, likes, or quantities when used according to the application's concurrency and data-model requirements.


53. Array Operations

Firestore supports atomic array operations such as adding or removing values.

Add an Item to an Array

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .update({
  'skills': FieldValue.arrayUnion(['Firebase']),
});

Remove an Item from an Array

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .update({
  'skills': FieldValue.arrayRemove(['Firebase']),
});

54. Nested Objects

Firestore documents can contain nested map structures.

await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .set({
  'name': 'John',
  'address': {
    'city': 'Mumbai',
    'country': 'India',
    'postalCode': '400001',
  },
});

55. Access Nested Data

final data = doc.data();
final address = data?['address'];

if (address != null) {
  print(address['city']);
  print(address['country']);
}

56. Subcollection Example

final userRef = FirebaseFirestore.instance
    .collection('users')
    .doc('user001');

await userRef
    .collection('orders')
    .doc('order001')
    .set({
  'product': 'Flutter Course',
  'price': 5000,
  'status': 'pending',
});

The resulting structure is:

users
  |
  +-- user001
       |
       +-- orders
            |
            +-- order001
                 |
                 +-- product
                 +-- price
                 +-- status

57. Read a Subcollection

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .doc('user001')
    .collection('orders')
    .get();

for (final doc in snapshot.docs) {
  print(doc.data());
}

58. Real-Time Chat Example

Firestore real-time listeners can be used for chat applications.

StreamBuilder>>(
  stream: FirebaseFirestore.instance
      .collection('messages')
      .orderBy('createdAt')
      .snapshots(),
  builder: (context, snapshot) {
    if (!snapshot.hasData) {
      return const CircularProgressIndicator();
    }

    final messages = snapshot.data!.docs;

    return ListView.builder(
      itemCount: messages.length,
      itemBuilder: (context, index) {
        final message = messages[index].data();

        return ListTile(
          title: Text(message['text'] ?? ''),
          subtitle: Text(message['sender'] ?? ''),
        );
      },
    );
  },
)

59. Pagination Concept

When a collection contains many documents, loading everything at once may not be appropriate. Firestore supports query cursors that can be used to retrieve data in pages.

A common pagination flow is:

First Page
   |
   v
Get Documents
   |
   v
Remember Last Document
   |
   v
Request Next Page
   |
   v
Display More Documents

Pagination should be designed around the application's sorting and filtering requirements.


60. Transactions

Transactions are useful when a group of reads and writes needs to operate consistently based on the current database values.

await FirebaseFirestore.instance.runTransaction(
  (transaction) async {
    final ref = FirebaseFirestore.instance
        .collection('products')
        .doc('product001');

    final snapshot = await transaction.get(ref);

    final currentStock = snapshot.data()?['stock'] ?? 0;

    if (currentStock > 0) {
      transaction.update(ref, {
        'stock': currentStock - 1,
      });
    }
  },
);

61. Batch Writes

Batch writes can be used when multiple write operations should be sent together.

final batch = FirebaseFirestore.instance.batch();

final userRef = FirebaseFirestore.instance
    .collection('users')
    .doc('user001');

final orderRef = FirebaseFirestore.instance
    .collection('orders')
    .doc('order001');

batch.set(userRef, {
  'name': 'John',
});

batch.set(orderRef, {
  'product': 'Flutter Course',
});

await batch.commit();

62. Error Handling

Firestore operations should handle errors because network problems, permissions, invalid operations, and other conditions can cause a request to fail.

try {
  await FirebaseFirestore.instance
      .collection('users')
      .doc('user001')
      .set({
    'name': 'John',
  });
} catch (e) {
  print('Firestore error: $e');
}

63. Firestore Exception Handling

You can handle Firestore-specific exceptions using FirebaseException.

try {
  await FirebaseFirestore.instance
      .collection('users')
      .doc('user001')
      .get();
} on FirebaseException catch (e) {
  print('Code: ${e.code}');
  print('Message: ${e.message}');
} catch (e) {
  print('Unexpected error: $e');
}

64. Loading, Error, Empty, and Success States

A Firestore-based screen should generally handle four important states:

  • Loading
  • Error
  • Empty
  • Success
if (snapshot.connectionState == ConnectionState.waiting) {
  return const CircularProgressIndicator();
}

if (snapshot.hasError) {
  return const Text('Unable to load data');
}

if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
  return const Text('No data available');
}

return const Text('Data loaded successfully');

65. Convert Firestore Documents to Dart Models

For larger applications, it is better to convert Firestore documents into Dart model classes instead of passing raw maps throughout the UI.

User Model

class UserModel {
  final String id;
  final String name;
  final String email;

  UserModel({
    required this.id,
    required this.name,
    required this.email,
  });

  factory UserModel.fromFirestore(
    DocumentSnapshot> doc,
  ) {
    final data = doc.data() ?? {};

    return UserModel(
      id: doc.id,
      name: data['name'] ?? '',
      email: data['email'] ?? '',
    );
  }
}

66. Using the User Model

final snapshot = await FirebaseFirestore.instance
    .collection('users')
    .get();

final users = snapshot.docs
    .map(UserModel.fromFirestore)
    .toList();

for (final user in users) {
  print(user.name);
  print(user.email);
}

67. Firestore Service Class

Firestore operations can be separated into a service class.

class UserService {
  final FirebaseFirestore _db = FirebaseFirestore.instance;

  Future addUser({
    required String id,
    required String name,
    required String email,
  }) async {
    await _db.collection('users').doc(id).set({
      'name': name,
      'email': email,
      'createdAt': FieldValue.serverTimestamp(),
    });
  }

  Future>> getUser(
    String id,
  ) {
    return _db.collection('users').doc(id).get();
  }

  Future updateUser(
    String id,
    Map data,
  ) {
    return _db.collection('users').doc(id).update(data);
  }

  Future deleteUser(String id) {
    return _db.collection('users').doc(id).delete();
  }
}

68. Recommended Project Structure

lib/
├── main.dart
├── firebase_options.dart
├── models/
│   ├── user_model.dart
│   └── product_model.dart
├── services/
│   ├── auth_service.dart
│   └── firestore_service.dart
├── screens/
│   ├── home_screen.dart
│   ├── users_screen.dart
│   └── products_screen.dart
├── widgets/
│   ├── user_card.dart
│   └── product_card.dart
└── repositories/
    └── user_repository.dart

69. Firestore and Flutter UI

A common Flutter architecture separates the UI from database operations.

Flutter UI
    |
    v
Controller / ViewModel
    |
    v
Repository / Service
    |
    v
Cloud Firestore
    |
    v
Firebase Backend

This structure makes the code easier to test, maintain, and expand as the application grows.


70. Example Product Application

Suppose an application stores products in Firestore:

products
  |
  +-- product001
  |     +-- name: "Laptop"
  |     +-- price: 65000
  |     +-- category: "Electronics"
  |
  +-- product002
        +-- name: "Phone"
        +-- price: 35000
        +-- category: "Electronics"

Add Product

await FirebaseFirestore.instance
    .collection('products')
    .add({
  'name': 'Laptop',
  'price': 65000,
  'category': 'Electronics',
});

Read Products

final snapshot = await FirebaseFirestore.instance
    .collection('products')
    .get();

Update Product

await FirebaseFirestore.instance
    .collection('products')
    .doc('product001')
    .update({
  'price': 62000,
});

Delete Product

await FirebaseFirestore.instance
    .collection('products')
    .doc('product001')
    .delete();

71. Offline Support

Cloud Firestore provides offline capabilities on supported platforms. The client can cache data that the application is actively using and can continue to read, write, listen to, and query cached data while offline. When connectivity returns, local changes are synchronized with the backend. Firestore Offline Data Documentation

Offline behavior should still be considered when designing user interfaces because users may temporarily have no network connection.


72. Firestore Console

The Firebase Console provides a visual interface for managing Firestore data.

You can use the console to:

  • Create collections.
  • Create documents.
  • Edit documents.
  • Delete documents.
  • Inspect document fields.
  • Review database data.
  • Manage indexes and database configuration.

Firestore data can be managed from the Firestore Data tab in the Firebase Console. Firestore Console Documentation


73. Firestore Indexes

Indexes help Firestore efficiently execute supported queries. Some compound queries require an index. When a required index is missing, Firestore can return an error containing a link to create the required index.

When designing queries, understand the fields used for filtering and sorting so that required indexes can be configured appropriately.


74. Firestore Security Best Practices

  • Do not leave production Firestore data publicly readable and writable.
  • Use Firebase Authentication for user identity.
  • Use Security Rules to control document access.
  • Use UID-based rules for user-specific documents.
  • Validate incoming data with Security Rules where appropriate.
  • Design queries to satisfy the constraints imposed by Security Rules.
  • Use App Check where appropriate as an additional protection layer.
  • Do not place secret server credentials inside a Flutter application.
  • Review rules before releasing the application.

Firebase recommends Authentication and Security Rules for mobile and web client access to Firestore. Firestore Security Rules Overview


75. Common Firestore Mistakes

Mistake Better Approach
Using incorrect collection/document paths Keep the Firestore data model clearly documented.
Loading an entire large collection unnecessarily Use filtering, limits, pagination, and appropriate queries.
Ignoring loading and error states Handle loading, error, empty, and success states.
Using raw maps everywhere Use Dart model classes for larger applications.
Ignoring Security Rules Design and test rules before production.
Assuming Security Rules filter query results Make queries satisfy the constraints required by the rules.
Calling database operations unnecessarily Use appropriate state management and caching patterns.
Ignoring offline behavior Design the UI to handle temporary network issues.

76. Firestore vs Realtime Database

Feature Cloud Firestore Realtime Database
Data Model Collections and documents JSON tree
Queries Rich querying capabilities Query capabilities differ
Real-Time Updates Supported Supported
Offline Support Supported on supported client platforms Supported
Hierarchical Data Documents and subcollections Nested JSON structure
Security Security Rules Security Rules

The appropriate Firebase database depends on the application's data model, query requirements, real-time needs, and other technical considerations.


77. Mini Project: Flutter User Management App

Create a Flutter application that uses Firebase Authentication and Cloud Firestore to manage users.

Required Features

  1. User registration.
  2. User login.
  3. Firebase Authentication.
  4. Store user profile in Firestore.
  5. Display current user information.
  6. Update profile information.
  7. Display a list of users where permitted by Security Rules.
  8. Delete a user profile document where permitted.
  9. Logout.
  10. Loading and error states.

Suggested Firestore Structure

users
  |
  +-- USER_UID
       |
       +-- name
       +-- email
       +-- phone
       +-- createdAt
       +-- profileImage

78. Mini Project: Product Management App

Create a product management application using Cloud Firestore.

Features

  • Add products.
  • Display products.
  • Search or filter products using supported queries.
  • Sort products.
  • Update products.
  • Delete products.
  • Display loading state.
  • Display empty state.
  • Display error state.
  • Use Security Rules to restrict write access.

79. Interview Questions

  1. What is Cloud Firestore?
  2. What is the difference between a collection and a document?
  3. What is a Firestore document ID?
  4. What are Firestore subcollections?
  5. How do you add Cloud Firestore to a Flutter project?
  6. What is FirebaseFirestore.instance?
  7. What is the difference between add() and set()?
  8. What is the difference between set() and update()?
  9. How do you retrieve a single Firestore document?
  10. How do you retrieve all documents from a collection?
  11. What is the difference between get() and snapshots()?
  12. How do you display real-time Firestore data in Flutter?
  13. How does StreamBuilder work with Firestore?
  14. How do you filter Firestore documents?
  15. What is where()?
  16. What is orderBy()?
  17. What is limit()?
  18. What are Firestore indexes?
  19. What are Firestore Security Rules?
  20. How do Firebase Authentication and Firestore work together?
  21. Why is a user's Firebase UID useful in Firestore?
  22. What is offline support in Firestore?
  23. What are Firestore transactions?
  24. What are batch writes?
  25. How can Firestore data be converted into Dart model classes?

80. Quick Revision

Concept Important API
Firestore Instance FirebaseFirestore.instance
Collection collection()
Document doc()
Create with Auto ID add()
Create/Replace set()
Update update()
Read Once get()
Real-Time Data snapshots()
Filter where()
Sort orderBy()
Limit limit()
Delete delete()
Server Timestamp FieldValue.serverTimestamp()
Increment FieldValue.increment()
Array Add FieldValue.arrayUnion()
Array Remove FieldValue.arrayRemove()
Transaction runTransaction()
Batch Write batch()

81. Learning Outcomes

After completing this topic, you should be able to:

  • Explain Cloud Firestore and its NoSQL data model.
  • Understand collections, documents, fields, and subcollections.
  • Configure Cloud Firestore in a Flutter application.
  • Add documents with automatic and custom IDs.
  • Read individual and multiple documents.
  • Update and delete Firestore data.
  • Use Firestore queries.
  • Filter and sort Firestore data.
  • Display Firestore data using FutureBuilder.
  • Display real-time Firestore data using StreamBuilder.
  • Use timestamps and atomic field operations.
  • Work with nested data and subcollections.
  • Use Firestore with Firebase Authentication.
  • Understand Firestore Security Rules.
  • Handle loading, error, empty, and success states.
  • Use Dart models and service classes for scalable applications.
  • Understand transactions, batch writes, pagination, and offline support.

82. Official Firebase Resources


83. JustAcademy Flutter Resources

For structured Flutter learning, practical development training, and additional Flutter topics, explore the following resources:


84. Summary

Cloud Firestore is a flexible NoSQL cloud database that stores data using collections and documents. Flutter applications can use the Cloud Firestore Flutter plugin to create, read, update, delete, query, and listen to application data.

Firestore can be combined with Firebase Authentication to create user-specific data structures, while Security Rules help control access to documents. Real-time listeners make Firestore useful for applications such as chat systems and live dashboards, while queries, indexes, transactions, batch writes, and offline support provide additional capabilities for building more advanced applications.

whatsapp